/*
 * mailcmd.c
 *
 *  Created on: 14/lug/2014
 *      Author: root
 */

#include "cmd.h"
#include <unistd.h>
#include "utils/sharedMemory.h"
#include "utils/semaphores.h"
#include "utils/mmap.h"
#include <assert.h>
#include <fcntl.h>
#include <ifaddrs.h>
#include "regExp.h"
#include "pksocket.h"



void parseCmd(char fromsocket[], PTRSESSION session, unsigned int * clientSockId){

	int actualindex = 0;
	int k=0, stop=0;
	char * cmd = NULL;

	while(stop < 1){
		k = actualindex;
		while(!isspace(fromsocket[k]) && fromsocket[k]!=':' && fromsocket[k]!='\0')k++;
		cmd = (char *)getMemory(k+1,CHAR_TYPE);
		memset(cmd,'\0',k+1);
		strncpy(cmd, &fromsocket[actualindex], k);
		session->cmd = decodeCmd(cmd,session->type);
		if((isspace(fromsocket[k]) || fromsocket[k]==':') && fromsocket[k]!='\0')k++;
		actualindex = k;
		if(session->type == POP3){
			switch(session->cmd){
				case USER:
					actualindex += parseUser(&fromsocket[k], session);
					stop = 1;
					break;

				case PASS:
					actualindex += parsePass(&fromsocket[k], session);
					stop = 1;
					break;

				case LIST:
					actualindex += parseList(&fromsocket[k], session);
					stop =1;
					break;

				case RETR:
					actualindex += parseRetr(&fromsocket[k], session);
					stop = 1;
					break;

				case DELE:
					actualindex += parseDele(&fromsocket[k], session);
					stop = 1;
					break;
				case QUIT:
					stop = 1;
					break;

				case RSET:
					stop = 1;
					break;

				case NOOP:
					addResponse(session->response, RESP_POP3_NOOP);
					stop = 1;
					break;

				case STAT:
				case APOP:
				case TOP:
				case UIDL:
					addResponse(session->response, RESP_502);
					break;

				case NONE:
				default:
					stop = 1;
					break;
			}
		}
		else if(session->type == SMTP){
			switch(session->cmd){
				case HELO:
					actualindex += parseHelo(&fromsocket[k], session);
					stop = 1;
					break;

				case MAIL:
					actualindex += parseMail(&fromsocket[k], session);
					stop = 1;
					break;

				case RCPT:
					actualindex += parseRcpt(&fromsocket[k], session);
					stop = 1;
					break;

				case DATA:
					parseData(session, clientSockId);
					stop = 1;
					break;

				case QUIT:
					addResponse(session->response, RESP_221);
					addRspParam(session->rspParams, LOCAL_DOMAIN);
					stop = 1;
					break;

				case RSET:
					//Annulla la transazione MAIL
					break;

				case NOOP:
					addResponse(session->response, RESP_220);
					stop = 1;
					break;

				case SEND:
				case SOML:
				case SAML:
				case VRFY:
				case EXPN:
				case TURN:
					addResponse(session->response, RESP_502);
					break;

				case NONE:
				default:
					addResponse(session->response, RESP_500);
					stop = 1;
					break;
			}
		}
		if(cmd != NULL){
			free(cmd);
			cmd  = NULL;
		}
	}
}


void executeCmd(PTRSESSION session, struct sockaddr_in * serverSmtpSocket, int isPop3, struct sockaddr_in * clientSockAddr, CNF_PTR configuration){

	//mailboxSemId= -1;

	struct flock fileLock;
	if(session->type == POP3){
		//comandi POP
		switch(session->cmd){
			case USER:
				if(isLocalUser(secretsFile, secretsFileSize, session->protocol.pop3.user) == 1){
					session->protocol.pop3.authState = USER_RCVD;
					addResponse(session->response, RESP_POP3_USR_OK);
				}
				else addResponse(session->response, RESP_POP3_USR_KO);
				break;

			case PASS:
				executePass(session, clientSockAddr, &fileLock, configuration->mailboxPath);
				break;

			case LIST:
				executeList(session);
				break;

			case RETR:
				executeRetr(session);
				break;

			case DELE:
				executeDele(session);
				break;
			case QUIT:
				executeQuit(session, &fileLock);
				break;

			case RSET:
				executeRset(session);
				break;

			case NOOP:
				addResponse(session->response, RESP_POP3_NOOP);
				break;

			default:
				addResponse(session->response, RESP_POP3_SYNTAX_KO);
				break;
		}
	}
	else if(session->type == SMTP){
		//Comandi SMTP
		switch(session->cmd){
			case HELO:
				executeHelo(session);
				break;

			case MAIL:
				executeMail(session, clientSockAddr);
				break;

			case RCPT:
				executeRcpt(session);
				break;

			case DATA:
				executeData(session, configuration);
				break;

			case QUIT:
//				addResponse(session->response, RESP_221);
				break;

			case RSET:
				//TODO: controllare se resettare anche altre property
				session->protocol.smtp.mailobject->state = NO_SESSION;
				addResponse(session->response, RESP_250);
				break;

			case NOOP:
				addResponse(session->response, RESP_220);
				break;

			default:
				addResponse(session->response, RESP_500);
				break;
		}
	}

}

/***
 * @Name: readData
 * @Prototype: char * readData(char *, unsigned int *, SESSION)
 * @Description: Descrizione
 * @Header files: mailcmd.h
 */

char * readData(char * data, unsigned int *clientSockId, PTRSESSION session){

	char * buffer = NULL, *tmp = NULL;
	int size = 0;



	if(data!=NULL && strcasecmp("\r\n.\r\n\r\n",&data[strlen(data)-7])==0){
		memset(&data[strlen(data)-7],'\0',7);
		return data;
	}

	buffer = readInput(buffer, clientSockId, session);

	if(buffer!=NULL){
		size += strlen(buffer);
		if(data!=NULL){
			tmp = data;
			size += strlen(data);
		}

		data = (char *)getMemory(size+1,CHAR_TYPE);
		memset(data,'\0',size+1);

		if(tmp != NULL){
			strcat(data,tmp);
		}

		if(buffer!=NULL){
			strcat(data,buffer);
		}

		if(tmp != NULL){
			free(tmp);
			tmp  = NULL;
		}

		if(buffer != NULL){
			free(buffer);
			buffer  = NULL;
		}

		data = readData(data, clientSockId,session);

	}

	return data;

}


void startSmtpListener(CNF_PTR configuration ,unsigned int * smtpServSockId, unsigned int * smtpClientSockId, struct sockaddr_in *serverSmtpSocket){
	struct sockaddr_in clientAddr;
	int sessionManagerPid =-1;
	if(isNull(configuration)==0){
		initServerSocket(&configuration->smtpPort, smtpServSockId, serverSmtpSocket);
		logMessage(INFO_LEV,"Avvio ascolto sulla porta SMTP");

		while(sessionManagerPid!=0){
			waitIncomingConnections(smtpServSockId, smtpClientSockId, &clientAddr);//serverSmtpSocket
			//fork processo gestione connessione
			if((sessionManagerPid = fork()) == 0){
				manageSession(smtpClientSockId, serverSmtpSocket, &clientAddr, SMTP, configuration);
			}

			sleep(1);
		}
	}
}


void startPop3Listener(CNF_PTR configuration ,unsigned int * pop3ServSockId, unsigned int * pop3ClientSockId, struct sockaddr_in *serverPop3Socket){
	struct sockaddr_in clientAddr;
	int sessionManagerPid =-1;
	if(isNull(configuration)==0){
		initServerSocket(&configuration->pop3Port, pop3ServSockId, serverPop3Socket);
		logMessage(INFO_LEV,"Avvio ascolto connessioni POP3");

		while(sessionManagerPid!=0){
			waitIncomingConnections(pop3ServSockId, pop3ClientSockId, &clientAddr);
			//fork processo gestione connessione

			if((sessionManagerPid = fork()) == 0){
				manageSession(pop3ClientSockId, serverPop3Socket, &clientAddr, POP3, configuration);
			}

			sleep(1);
		}
	}
}

char * readInput(char * input, unsigned int * clientSockId, PTRSESSION session){
	time_t now = time(NULL);
	int timeout;
	if(session->lastAccessTime == 0){
		session->lastAccessTime = now;
	}

	if(((timeout = now-session->lastAccessTime) < MIN25)){
		input = readSockData(clientSockId);
	}
	else{
		addResponse(session->response, RESP_221);//Imposto la chiusura del canale per timeout
		return NULL;
	}
	return input;
}

int isProtocolError(PTRSESSION session){
	int k = 0;
	int bool = 0;
	while(session->response[k] != RESP_NULL && k < MAX_RSP){
		if(
			session->response[k] == RESP_421 ||
			session->response[k] == RESP_422 ||
			session->response[k] == RESP_451 ||
			session->response[k] == RESP_452 ||
			session->response[k] == RESP_500 ||
			session->response[k] == RESP_501 ||
			session->response[k] == RESP_502 ||
			session->response[k] == RESP_503 ||
			session->response[k] == RESP_523 ||
			session->response[k] == RESP_550 ||
			session->response[k] == RESP_551 ||
			session->response[k] == RESP_552 ||
			session->response[k] == RESP_553 ||
			session->response[k] == RESP_POP3_USR_KO ||
			session->response[k] == RESP_POP3_PASS_KO_LCK ||
			session->response[k] == RESP_POP3_PASS_KO_WP ||
			session->response[k] == RESP_POP3_LIST_NO_ID ||
			session->response[k] == RESP_POP3_RTR_KO ||
			session->response[k] == RESP_POP3_STATUS_KO ||
			session->response[k] == RESP_POP3_DELE_KO)
		{
			bool = bool || 1;
		}
		else {
			bool = bool || 0;
		}
		k++;
	}
	return bool;
}

void manageSession(unsigned int * clientSockId, struct sockaddr_in *serverSocket, struct sockaddr_in *clientAddr, STYPE sessionType, CNF_PTR configuration){

	char * input = NULL;
	char * response = NULL;
	struct session session;

	//Imposto la sessione
	initSession(&session, serverSocket, clientAddr, clientSockId, sessionType);

	//Invio greetings
	if(session.type == POP3){
		addResponse(session.response, RESP_POP3_SRV_OK);
	}
	else if(session.type == SMTP){
		addResponse(session.response, RESP_220);
		addRspParam(session.rspParams, LOCAL_DOMAIN);
	}

	response = generateResponse(session.response, session.rspParams, session.type);
	sendSockData(clientSockId, response);
	clearResponse(session.response);
	clearRspParam(session.rspParams);

	free(response);
	response = NULL;
	//fine greetings

	while(session.cmd!=QUIT){
		//aspetto e ricevo il comando dal socket
		//Imposto un timeout di max 25 min fra un comando e
		//l'altro ... provvisorio.
		input = readInput(input,clientSockId, &session);

		if(isInResponse(session.response, RESP_221)){
			break; //Errore di timeout in ricezione
		}
		//identifico l'operazione
		parseCmd(input, &session, clientSockId);
		if(!isProtocolError(&session)){
			//Eseguo il comando se dopo parsecmd il valore della response non è un errore
			executeCmd(&session, serverSocket, sessionType, clientAddr, configuration);
		}
		if(session.response[0] != RESP_NULL){
			//genero risposta al client

			response = generateResponse(session.response, session.rspParams, session.type);

			//invio la risposta
			sendSockData(clientSockId, response);
		}
		if(input != NULL){
			free(input);
			input = NULL;
		}

		if(response != NULL){
			free(response);
			response = NULL;
		}

		clearResponse(session.response);
		clearRspParam(session.rspParams);

	}
	closeBidirSocket(clientSockId);
	exit(0);
}

void initSession(PTRSESSION session,struct sockaddr_in *serverSocket, struct sockaddr_in * clientAddr, unsigned int * clientSockId ,STYPE sessionType){

	int k;
	socklen_t addrlen = sizeof *clientAddr;
	session->cmd = NONE;
	session->lastAccessTime = 0;

	session->serv_ip_address = (char *)getMemory(addrlen+1,CHAR_TYPE);
	memset(session->serv_ip_address,'\0',addrlen+1);
	//IP sever chiamato dal client
	if(getsockname(*clientSockId, (struct sockaddr *)clientAddr, &addrlen) == -1){
		notifyError(ERR_SOCKINFO_READ, 1, 0);
	}

	if(inet_ntop(AF_INET, &clientAddr->sin_addr,session->serv_ip_address,addrlen)==NULL){
		notifyError(ERR_READ_IP, 1, 0);
	}

	//IP del client
	session->ip_address = (char *)getMemory(addrlen+1,CHAR_TYPE);
	memset(session->ip_address,'\0',addrlen+1);
	if(getpeername(*clientSockId, (struct sockaddr *)clientAddr, &addrlen) == -1){
		notifyError(ERR_SOCKINFO_READ, 1, 0);
	}

	if(inet_ntop(AF_INET,&clientAddr->sin_addr,session->ip_address,addrlen)==NULL){
		notifyError(ERR_READ_IP, 1, 0);
	}

	session->type = sessionType;

	switch(session->type){
		case SMTP:
			session->protocol.smtp.clienthostname = NULL;
			session->protocol.smtp.mailobject = NULL;
			session->protocol.smtp.mailobject = initMailObject(session->protocol.smtp.mailobject);
			break;

		case POP3:
			session->protocol.pop3.user = NULL;
			session->protocol.pop3.pass = NULL;
			session->protocol.pop3.msgID = NULL;
			session->protocol.pop3.msgList = NULL;
			session->protocol.pop3.authState = NO_STATE;
			session->protocol.pop3.mboxfd = NULL;
			break;
		default: break;
	}

	for(k = 0; k < MAX_RSP; k++){
		session->response[k] = RESP_NULL;
	}

	for(k = 0; k < MAX_RSP_PAR; k++){
		session->rspParams[k] = NULL;
	}


}

int clearResponse(RESPONSE resps[]){
	int k, bool = 0;
	for(k = 0; k < MAX_RSP; k++){
		if(resps[k] != RESP_NULL){
			resps[k] = RESP_NULL;
			bool = bool || 1;
		}
	}
	return bool;
}

int addResponse(RESPONSE resps[], RESPONSE toAdd){
	int k, bool = 0;
	for(k = 0; k < MAX_RSP; k++){
		if(resps[k] == RESP_NULL){
			resps[k] = toAdd;
			bool = 1;
			break;
		}
	}
	return bool;
}

int isInResponse(RESPONSE resps[], RESPONSE toCheck){
	int k, bool = 0;
	for(k = 0; k < MAX_RSP; k++){
		if(resps[k] != RESP_NULL){
			if(resps[k] == toCheck){
				bool = 1;
			}
		}
	}
	return bool;
}

int addRspParam(char **params, char *toAdd){
	int k, bool = 0, size = 0;
	for(k = 0; k < MAX_RSP_PAR; k++){
		if(params[k] == NULL){
			size = strlen(toAdd)+1;
			params[k] = (char *)getMemory(size,CHAR_TYPE);
			memset(params[k],'\0', size);
			strcat(params[k], toAdd);
			bool = 1;
			break;
		}
	}
	return bool;
}

int clearRspParam(char *params[]){
	int k, bool = 0;
	for(k = 0; k < MAX_RSP_PAR; k++){
		if(params[k] != NULL){
			free(params[k]);
			params[k] = NULL;
			bool = bool || 1;
		}
	}
	return bool;
}


PMAIL initMailObject(PMAIL mailobject){

	int k = 0;


	if(mailobject!=NULL){
		if(mailobject->sender != NULL){
			free(mailobject->sender);
		}
		mailobject->sender = NULL;

		if(mailobject->receiversTo!=NULL){
			while(mailobject->receiversTo[k]!='\0'){
				free(mailobject->receiversTo[k]);
				k++;
			}
			free(mailobject->receiversTo);
			mailobject->receiversTo = NULL;
		}
		mailobject->receiversTo = (char **)getMemory(256, PCHAR_TYPE);
		memset(mailobject->receiversTo,'\0',256);

		if(mailobject->data!=NULL){
			free(mailobject->data);
		}
		mailobject->data = NULL;
	}
	else{
		mailobject = getMemory(1,MAILCMD_TYPE);
		mailobject->sender = NULL;
		mailobject->receiversTo = (char **)getMemory(256, PCHAR_TYPE);
		memset(mailobject->receiversTo,'\0',256);
		mailobject->data = NULL;
	}
	mailobject->state = NO_SESSION;
	return mailobject;
}


//TODO: generateResponse deve avere com argomento un insieme di response code e
//restituire un array di puntatori a carattere, uno per ogni response decodificata nella risposta attuale
char * generateResponse(RESPONSE respcodes[], char ** params, STYPE protocol){

	char *msgFormat = NULL, *tmp = NULL, *tmp2 = NULL, *rspToReturn = NULL;

	int size = 0, k, i, npar = 0, respCodePresent = 0, idx_par = 0;

 // Per ogni codice resp
	for(k = 0; k < MAX_RSP && respcodes[k] != RESP_NULL; k++){

//		if(respcodes[k] == RESP_NULL){
//			break;
//		}

		if(rspToReturn!=NULL){
			tmp = rspToReturn;
		}
		//Decode del codice e numero parametri eventuali

		msgFormat = decodeRespCode(respcodes[k], &npar, &respCodePresent);//Aggiungere con lista di parametri e offset (k)
		size = strlen(msgFormat);
		//Se ci sono parametri ...
		if(npar > 0){
			for(i = idx_par; i < npar && i< MAX_RSP_PAR; i++){
				if(params[i] != NULL){
					size += strlen(params[i]);
					idx_par = i;
				}
			}

			size++;

			tmp2 = (char *) getMemory(size, CHAR_TYPE);
			memset(tmp2, '\0', size);
			if(respCodePresent){
				switch(npar){
					case 1:
						sprintf(tmp2, msgFormat, respcodes[k], params[0]);
						break;
					case 2:
						sprintf(tmp2, msgFormat, respcodes[k], params[0], params[1]);
						break;
					case 3:
						sprintf(tmp2, msgFormat, respcodes[k], params[0], params[1], params[2]);
						break;

				}
			}
			else {
				switch(npar){
					case 1:
						sprintf(tmp2, msgFormat, params[0]);
						break;
					case 2:
						sprintf(tmp2, msgFormat, params[0], params[1]);
						break;
					case 3:
						sprintf(tmp2, msgFormat, params[0], params[1], params[2]);
						break;

				}
			}
			idx_par++;//Aumento l'indice per continuare dal parametro successivo
			size = (tmp == NULL ? 0 : strlen(tmp)) + strlen(tmp2)+1+5;//5 sono i caratteri per -ERR +OK o il codice di response a 3 cifre e \0
			rspToReturn = (char *) getMemory(size, CHAR_TYPE);
			memset(rspToReturn, '\0', size);

			if(tmp != NULL){
				strcat(rspToReturn, tmp);
				free(tmp);
				tmp = NULL;
			}

			strcat(rspToReturn, tmp2);
			free(tmp2);
			tmp2 = NULL;




		}
		else{
			rspToReturn = (char *) getMemory(size, CHAR_TYPE);
			memset(rspToReturn, '\0', size);
			if(respCodePresent){
				sprintf(rspToReturn, msgFormat, respcodes[k]);
			}
			else{
				strcat(rspToReturn, msgFormat);
			}
		}

		if(protocol == POP3){
			//La memoria del messaggio e' allocata dinamicamente solo per POP3
			free(msgFormat);
		}
	}
	return rspToReturn;
}

char * decodeRespCode(RESPONSE respCode, int * npar, int *respCodePresent){
	char * msg = NULL;
	int size = 0;
	switch(respCode){

	case RESP_214:
		msg = RESP_214_MSG;
		*respCodePresent = 1;
		break;

	case RESP_220:
		msg = RESP_220_MSG;
		*respCodePresent = 1;
		*npar = 1;
		break;

	case RESP_221:
		msg = RESP_221_MSG;
		*respCodePresent = 1;
		*npar = 1;
		break;

	case RESP_250:
		msg = RESP_250_MSG;
		*respCodePresent = 1;
		break;

	case RESP_354:
		msg = RESP_354_MSG;
		*respCodePresent = 1;
		break;

	case RESP_421:
		msg = RESP_421_MSG;
		*respCodePresent = 1;
		*npar = 1;
		break;

	case RESP_422:
		msg = RESP_422_MSG;
		*respCodePresent = 1;
		break;

	case RESP_451:
		msg = RESP_451_MSG;
		*respCodePresent = 1;
		break;

	case RESP_452:
		msg = RESP_452_MSG;
		*respCodePresent = 1;
		break;

	case RESP_500:
		msg = RESP_500_MSG;
		*respCodePresent = 1;
		break;

	case RESP_501:
		msg = RESP_501_MSG;
		*respCodePresent = 1;
		break;

	case RESP_502:
		msg = RESP_502_MSG;
		*respCodePresent = 1;
		break;

	case RESP_503:
		msg = RESP_503_MSG;
		*respCodePresent = 1;
		break;

	case RESP_523:
		msg = RESP_523_MSG;
		*respCodePresent = 1;
		break;

	case RESP_550:
		msg = RESP_550_MSG;
		*respCodePresent = 1;
		break;

	case RESP_551:
		msg = RESP_551_MSG;
		*respCodePresent = 1;
		*npar = 1;
		break;

	case RESP_552:
		msg = RESP_552_MSG;
		*respCodePresent = 1;
		break;

	case RESP_553:
		msg = RESP_553_MSG;
		*respCodePresent = 1;
		break;

	case RESP_POP3_SRV_OK:
		size = strlen(POP3_PREFIX_OK)+strlen(RESP_POP3_SRV_OK_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_OK);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_SRV_OK_MSG);
		break;

	case RESP_POP3_USR_OK:
		size = strlen(POP3_PREFIX_OK)+strlen(RESP_POP3_USR_OK_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_OK);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_USR_OK_MSG);
		break;

	case RESP_POP3_USR_KO:
		size = strlen(POP3_PREFIX_ERR)+strlen(RESP_POP3_USR_KO_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_ERR);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_USR_KO_MSG);
		break;

	case RESP_POP3_PASS_OK:
		size = strlen(POP3_PREFIX_OK)+strlen(RESP_POP3_PASS_OK_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_OK);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_PASS_OK_MSG);
		break;

	case RESP_POP3_PASS_KO_LCK:
		size = strlen(POP3_PREFIX_ERR)+strlen(RESP_POP3_PASS_KO_LCK_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_ERR);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_PASS_KO_LCK_MSG);
		break;

	case RESP_POP3_PASS_KO_WP:
		size = strlen(POP3_PREFIX_ERR)+strlen(RESP_POP3_PASS_KO_WP_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_ERR);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_PASS_KO_WP_MSG);
		break;

	case RESP_POP3_NOOP:
		size = strlen(POP3_PREFIX_OK)+strlen(RESP_POP3_NOOP_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_OK);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_NOOP_MSG);
		break;

	case RESP_POP3_LIST_OK:
		size = strlen(POP3_PREFIX_OK)+strlen(RESP_POP3_LIST_OK_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_OK);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_LIST_OK_MSG);
		*npar = 3;
		break;

	case RESP_POP3_LIST_ID_OK:
		size = strlen(POP3_PREFIX_OK)+strlen(RESP_POP3_LIST_ID_OK_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_OK);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_LIST_ID_OK_MSG);
		*npar = 1;
		break;

	case RESP_POP3_RTR_OK:
		size = strlen(POP3_PREFIX_OK)+strlen(RESP_POP3_RTR_OK_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_OK);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_RTR_OK_MSG);
		*npar = 1;
		break;

	case RESP_POP3_DELE_OK:
		size = strlen(POP3_PREFIX_OK)+strlen(RESP_POP3_DELE_OK_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_OK);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_DELE_OK_MSG);
		break;

	case RESP_POP3_DELE_KO:
		size = strlen(POP3_PREFIX_ERR)+strlen(RESP_POP3_DELE_KO_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_ERR);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_DELE_KO_MSG);
		break;

	case RESP_POP3_QUIT:
		size = strlen(POP3_PREFIX_OK)+strlen(RESP_POP3_QUIT_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_OK);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_QUIT_MSG);
		break;

	case RESP_POP3_RSET:
		size = strlen(POP3_PREFIX_OK)+strlen(RESP_POP3_RSET_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_OK);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_RSET_MSG);
		break;

	case RESP_POP3_LIST_NO_ID:
		size = strlen(POP3_PREFIX_ERR)+strlen(RESP_POP3_LIST_NO_ID_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_ERR);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_LIST_NO_ID_MSG);
		break;

	case RESP_POP3_RTR_KO:
		size = strlen(POP3_PREFIX_ERR)+strlen(RESP_POP3_RTR_KO_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_ERR);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_RTR_KO_MSG);
		break;

	case RESP_POP3_STATUS_KO:
		size = strlen(POP3_PREFIX_ERR)+strlen(RESP_POP3_STATUS_KO_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_ERR);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_STATUS_KO_MSG);
		break;

	case RESP_POP3_SYNTAX_KO:
		size = strlen(POP3_PREFIX_ERR)+strlen(RESP_POP3_SYNTAX_KO_MSG)+1; // ' '
		msg = (char *)getMemory(size+1, CHAR_TYPE);
		memset(msg, '\0', size+1);
		strcat(msg, POP3_PREFIX_ERR);
		strcat(msg, " ");
		strcat(msg, RESP_POP3_SYNTAX_KO_MSG);
		break;

	default:break;
	}
	return msg;
}


CMD decodeCmd (char * cmdstr, STYPE sessionType){
	CMD cmd = NONE;
	if(sessionType == POP3){
		if(strcasecmp(cmdstr, STR_USER)==0){
			cmd =  USER;
		}
		else if(strcasecmp(cmdstr, STR_PASS)==0){
			cmd =  PASS;
		}
		else if(strcasecmp(cmdstr, STR_LIST)==0){
			cmd =  LIST;
		}
		else if(strcasecmp(cmdstr, STR_RETR)==0){
			cmd =  RETR;
		}
		else if(strcasecmp(cmdstr, STR_PASS)==0){
			cmd =  DELE;
		}
		else if(strcasecmp(cmdstr, STR_QUIT)==0){
			cmd =  QUIT;
		}
		else if(strcasecmp(cmdstr, STR_RSET)==0){
			cmd =  RSET;
		}
		else if(strcasecmp(cmdstr, STR_NOOP)==0){
			cmd =  NOOP;
		}
		else if(strcasecmp(cmdstr, STR_STAT)==0){
			cmd =  STAT;
		}
		else if(strcasecmp(cmdstr, STR_APOP)==0){
			cmd =  APOP;
		}
		else if(strcasecmp(cmdstr, STR_TOP)==0){
			cmd =  TOP;
		}
		else if(strcasecmp(cmdstr, STR_UIDL)==0){
			cmd =  UIDL;
		}
	}
	else if(sessionType == SMTP){
		if(strcasecmp(cmdstr, STR_HELO)==0){
			cmd =  HELO;
		}
		else if(strcasecmp(cmdstr, STR_MAIL)==0){
			cmd =  MAIL;
		}
		else if(strcasecmp(cmdstr, STR_RCPT)==0){
			cmd =  RCPT;
		}
		else if(strcasecmp(cmdstr, STR_DATA)==0){
			cmd =  DATA;
		}
		else if(strcasecmp(cmdstr, STR_QUIT)==0){
			cmd =  QUIT;
		}
		else if(strcasecmp(cmdstr, STR_RSET)==0){
			cmd =  RSET;
		}
		else if(strcasecmp(cmdstr, STR_NOOP)==0){
			cmd =  NOOP;
		}
		else if(strcasecmp(cmdstr, STR_SEND)==0){
			cmd =  SEND;
		}
		else if(strcasecmp(cmdstr, STR_SOML)==0){
			cmd =  SOML;
		}
		else if(strcasecmp(cmdstr, STR_SAML)==0){
			cmd =  SAML;
		}
		else if(strcasecmp(cmdstr, STR_VRFY)==0){
			cmd =  VRFY;
		}
		else if(strcasecmp(cmdstr, STR_EXPN)==0){
			cmd =  EXPN;
		}
		else if(strcasecmp(cmdstr, STR_TURN)==0){
			cmd =  TURN;
		}

	}
	return cmd;
}

char * buildMessageID(PTRSESSION session, int *fd, char * usrname){
	char *msgID = NULL;
	int progressive = 0, size = 0;

	if(*fd != -1){
		progressive = getNextMsgId(fd);
		lseek(*fd, 0, SEEK_SET);
		//4 = '<','>','@','\0'   15= MAX_LENGTH IP
		size = 3+strlen(usrname)+15+17;
		msgID = (char *)getMemory(size+1,CHAR_TYPE);
		memset(msgID,'\0',size+1);
		sprintf(msgID,"%s                 : <%d@%s>", MSG_ID, progressive,usrname);
	}
	return msgID;
}

/**
 * Headers
 *
 *
 * Date:     26 Aug 76 1429 EDT
 * From:     Jones@Registry.Org
 * To:       Smith@Registry.Org
 */


char * buildMessage(PTRSESSION session, int *fd, char *usrname){


	char *msg = NULL, *chunk = NULL, * date = NULL, * msgID;
	int size = 0, receiversBytes = 0, k = 0, isOkMsg = 0;
	time_t t = time(NULL);
	struct tm tm = *gmtime(&t);

	msg = (char * )getMemory(MAX_MSG_SIZE, CHAR_TYPE);
	memset(msg, '\0', MAX_MSG_SIZE);

	//Intestazione e data
	chunk = (char *)getMemory(1024, CHAR_TYPE);
	memset(chunk,'\0',1024);
	date = (char *)getMemory(80,CHAR_TYPE);
	memset(date,'\0',80);




	sprintf(date,"%s                       : %d-%d-%d %d:%d:%d UTC",
			DATE,
			tm.tm_year + 1900, tm.tm_mon + 1,
			tm.tm_mday,
			tm.tm_hour,
			tm.tm_min,
			tm.tm_sec);

	sprintf(chunk,"%s %s\r\n%s\r\n%s                       : <%s>\r\n",
			FROM,session->protocol.smtp.mailobject->sender, date, FROM, session->protocol.smtp.mailobject->sender);

	strcat(msg, chunk);
	free(date);
	date = NULL;
	free(chunk);
	chunk = NULL;

	//TO:
	if((receiversBytes = receiversByteSize(session))>0){
		strcat(msg,TO);
		strcat(msg,"                         : ");
		size = 6 + (receiversBytes)+1;
		chunk = (char *)getMemory(size,CHAR_TYPE);
		memset(chunk,'\0',size);

		k=0;
		while(session->protocol.smtp.mailobject->receiversTo[k]!='\0' && session->protocol.smtp.mailobject->receiversTo[k]!= NULL){
			strcat(chunk,"<");
			strcat(chunk,session->protocol.smtp.mailobject->receiversTo[k]);
			strcat(chunk,">");
			if(session->protocol.smtp.mailobject->receiversTo[k+1]!='\0'){
				strcat(chunk,";");
			}
			k++;
		}
		/*Se non ci sono destinatari per la mail*/
		if(k==0)return NULL;
		strcat(chunk,"\r\n");

		strcat(msg, chunk);
		free(chunk);
		chunk = NULL;
	}
	else isOkMsg = 1;

	if(isOkMsg == 0){

		msgID = buildMessageID(session, fd, usrname);
		if(msgID==NULL){
			addResponse(session->response, RESP_451);
		}
		strcat(msg,msgID);
		strcat(msg,"\r\n\r\n");
		free(msgID);
		msgID = NULL;

		size = 2 + ((session->protocol.smtp.mailobject->data = substituteString(session->protocol.smtp.mailobject->data,"From", ">From"))!=NULL ? strlen(session->protocol.smtp.mailobject->data) : 0) +1;
		chunk = (char *)getMemory(size+1,CHAR_TYPE);
		memset(chunk,'\0',size+1);
		sprintf(chunk,"%s\r\n", session->protocol.smtp.mailobject->data!=NULL ? session->protocol.smtp.mailobject->data : "");
		strcat(msg, chunk);
		free(chunk);
		chunk = NULL;
	}
	if(isOkMsg == 0){
		return msg;
	}
	else return NULL;
}



void writeMailToBox( char * filename, PTRSESSION session, char *user){
	struct flock fl;
	int fd = -1;
	int new = 0;
	char * msg = NULL;
	int maildropSemId = -1;

	maildropSemId = getMBoxSem(user);
	if(maildropSemId >0){
		binSemWait(maildropSemId);

		fd = *(int *)openOrCreateFile(filename, WRITE ,&new);

		if(fd != -1){
			fl.l_type   = F_WRLCK;
			fl.l_whence = SEEK_END;
			fl.l_start  = 0;
			fl.l_len    = 0;
			fl.l_pid    = getpid();
			fcntl(fd, F_SETLKW, &fl);
			/*Composizione messaggio ARPA*/
			msg = buildMessage(session, &fd, user);
			lseek(fd, 0, SEEK_END);
			writeFile(&fd, msg);
			free(msg);
			fl.l_type   = F_UNLCK;
			fcntl(fd, F_SETLK, &fl);
			closeFile(&fd);
		}
		binSemPost(maildropSemId);
	}
}


int receiversByteSize(PTRSESSION session){
	int k = 0;
	int size = 0;
	if(session->protocol.smtp.mailobject->receiversTo!=NULL){
		while(session->protocol.smtp.mailobject->receiversTo[k]!='\0'){
			//+2 = '<' , '>' e ';'
			size += strlen(session->protocol.smtp.mailobject->receiversTo[k])+3;
			if(session->protocol.smtp.mailobject->receiversTo[k+1]!='\0'){
				size++;
			}
			k++;
		}
	}
	return size;
}

int parseHelo(char * input, PTRSESSION session){
		int k = 0;
		int start = 0;
		while(isspace(input[k]))k++;
		start = k;
		k++;
		while(!isspace(input[k]))k++;
		if(session->protocol.smtp.clienthostname!=NULL){
			free(session->protocol.smtp.clienthostname);
			session->protocol.smtp.clienthostname = NULL;
		}
		session->protocol.smtp.clienthostname = (char *)getMemory(k-start+1, CHAR_TYPE);
		memset(session->protocol.smtp.clienthostname, '\0', k-start+1);
		strncpy(session->protocol.smtp.clienthostname, &input[start],k-start);
		return k;
}

int parseMail(char *input, PTRSESSION session){

	char * buffer = NULL;
	int k = 0, actualindex = 0;

	if(session->protocol.smtp.mailobject->state == NO_SESSION){
		while((input[k]!=':' && input[k]!='\0')) k++;
		k++;//Comprendo anche i ':' del from
		buffer = (char *)getMemory(k+1, CHAR_TYPE);
		memset(buffer,'\0',k+1);
		strncpy(buffer,input,k);//leggo il FROM:

		if(strcasecmp(buffer,STR_FROM)==0){
			actualindex = k;
			if(session->protocol.smtp.mailobject->sender != NULL){
				free(session->protocol.smtp.mailobject->sender);
				session->protocol.smtp.mailobject->sender = NULL;
			}
			session->protocol.smtp.mailobject->sender = (char *)getMemory(256, PCHAR_TYPE);
			memset(session->protocol.smtp.mailobject->sender, '\0',256);
			/*Non sostituire condizione con isspace!*/
			while(input[k]!='\0' && input[k]!='\r'){
				//Raggiungo la prima angolare aperta
				while(input[k]!='<' && input[k]!='\0' && isspace(input[k]) )k++; //&& input[k]!='\r'
				//Oltrepasso l'angolare e salvo l'indice di inzio
				if(input[k]=='<')k++;
				else{
					addResponse(session->response, RESP_501);
					break;
				}
				actualindex = k;
				//cerco l'angolare chiusa o la fine
				while(input[k]!='>' && input[k]!='\0' && input[k]!='\r')k++;
				if(input[k]=='>'){
					session->protocol.smtp.mailobject->sender = (char *)getMemory(k-actualindex+1,CHAR_TYPE);
					memset(session->protocol.smtp.mailobject->sender,'\0',k-actualindex+1);
					strncpy(session->protocol.smtp.mailobject->sender,&input[actualindex],k-actualindex);
					k++;
					actualindex = k;
					if(isLocalUser(secretsFile, secretsFileSize, session->protocol.smtp.mailobject->sender)!=0){
						/*
						 * Se l'utente locale vuole inviare una mail devo impedirlo
						 * */
						session->protocol.smtp.mailobject->mailType = OUTCOMING;

					}
					else {
						session->protocol.smtp.mailobject->mailType = INCOMING;
						session->protocol.smtp.mailobject->state = MAIL_RCVD;
						addResponse(session->response, RESP_250);
						break;
					}
				}
				else{
					addResponse(session->response, RESP_501);
					break;
				}
			}
		}
		else{
			addResponse(session->response, RESP_500);//OK comando non riconosciuto
		}
		if(buffer != NULL){
			free(buffer);
			buffer = NULL;
		}
	}
	else{
		addResponse(session->response, RESP_503);
	}
	return k;

}

int parseRcpt(char * input, PTRSESSION session){

	int j = 0, k = 0, actualindex = 0, i= 0, l = 0, j_actualRcpt = 0;
	char * buffer = NULL;
	char username[256] = {0};
	char domain[256] = {0};

	if(session->protocol.smtp.mailobject->state == MAIL_RCVD || session->protocol.smtp.mailobject->state == RCPT_RCVD){
		clearResponse(session->response);
		if(session->protocol.smtp.mailobject->receiversTo == NULL){
			session->protocol.smtp.mailobject->receiversTo = (char **)getMemory(256, PCHAR_TYPE);
			memset(session->protocol.smtp.mailobject->receiversTo,'\0',256);
		}
		else{
			while(session->protocol.smtp.mailobject->receiversTo[j]!='\0')j++;
		}

		while((input[k]!=':' && input[k]!='\0'))k++;
		if(input[k]==':')k++;//posiziono k per ricomprendere i due punti
		buffer = (char *)getMemory(256, CHAR_TYPE);
		memset(buffer,'\0',256);
		strncpy(buffer,input,k);//leggo il TO:
		if(strcasecmp(buffer,STR_TO)==0){
			while(isspace(input[k]) && input[k]!='\0')k++;
			actualindex = k;
			while(!isspace(input[k]) && input[k]!='\0') {//!='\r' && input[k+1]!='\n'
				if(j_actualRcpt > 0 && input[k]!=';'){
					addResponse(session->response, RESP_501);
					break;
				}
				//Raggiungo la prima angolare aperta
				while(input[k]!='<' && input[k]!='\0')k++;
				//Oltrepasso l'angolare e salvo l'indice di inzio
				k++;
				actualindex = k;
				//cerco l'angolare chiusa o la fine
				while(input[k]!='>' && input[k]!='\0')k++;

				session->protocol.smtp.mailobject->receiversTo[j+j_actualRcpt]= (char *)getMemory(k-actualindex+1,CHAR_TYPE);
				memset(session->protocol.smtp.mailobject->receiversTo[j+j_actualRcpt],'\0',k-actualindex+1);
				strncpy(session->protocol.smtp.mailobject->receiversTo[j+j_actualRcpt],&input[actualindex],k-actualindex);
				i = 0;
				while(session->protocol.smtp.mailobject->receiversTo[j+j_actualRcpt][i]!='\0' && session->protocol.smtp.mailobject->receiversTo[j][i]!='@')i++;
				l = i+1;
				if(session->protocol.smtp.mailobject->receiversTo[j+j_actualRcpt][i]!='@'){
					addResponse(session->response, RESP_501);
					break;
				}
				strncpy(username, session->protocol.smtp.mailobject->receiversTo[j+j_actualRcpt], i);

				while(session->protocol.smtp.mailobject->receiversTo[j+j_actualRcpt][l]!='\0')l++;

				strncpy(domain, &(session->protocol.smtp.mailobject->receiversTo[j+j_actualRcpt][i+1]), l);

				if(strcasecmp(LOCAL_DOMAIN, domain)==0 || strcasecmp(LOCAL_IP_ADDRESS, domain)==0){
					//se il dominio e' quello del server o il suo ip
					//Se il destinatario non è un utente locale lo rimuovo dalla lista dei destinatari e ritorno errore
					if(isLocalUser(secretsFile, secretsFileSize, username)==1){
						strncpy(domain, &session->protocol.smtp.mailobject->receiversTo[j+j_actualRcpt][i+1], l);
					}
					else{
						//Se il destinatario non è locale impedire l'invio della mail
						addResponse(session->response, RESP_551);
					}
				}
				else{
					addResponse(session->response, RESP_551);
				}
				j_actualRcpt++;
				k++;
			}
		}
		else{
			addResponse(session->response, RESP_500);
		}
		if(buffer != NULL){
			free(buffer);
			buffer = NULL;
		}
	}
	else{
		addResponse(session->response, RESP_503);
	}
	return k;
}

void parseData(PTRSESSION session, unsigned int *clientSockId){

	char * response = NULL;

	if(session->protocol.smtp.mailobject->state == RCPT_RCVD){
		addResponse(session->response, RESP_354);
		response = generateResponse(session->response, session->rspParams, session->type);
		sendSockData(clientSockId, response);
		if(response != NULL){
			free(response);
			response = NULL;
		}
		clearResponse(session->response);

		session->protocol.smtp.mailobject->data = readData(session->protocol.smtp.mailobject->data,clientSockId, session);
		addResponse(session->response, RESP_250);

	}
	else{
		addResponse(session->response, RESP_503);
	}
}


int parseUser(char * input, PTRSESSION session){
	int k = 0;
	if(session->protocol.pop3.authState==NO_STATE){
		while(!(isspace(input[k])))k++;

		if(session->protocol.pop3.user!=NULL){
			free(session->protocol.pop3.user);
			session->protocol.pop3.user = NULL;
		}
		session->protocol.pop3.user = (char *)getMemory(k+1, CHAR_TYPE);
		memset(session->protocol.pop3.user, '\0', k+1);
		strncpy(session->protocol.pop3.user, &input[0],k);
	}
	else{
		addResponse(session->response, RESP_POP3_STATUS_KO);
	}
	return k;
}

int parsePass(char *input, PTRSESSION session){
	int k = 0;
	if(session->protocol.pop3.authState==USER_RCVD){
		while(!(isspace(input[k]))) k++; // && fromsocket[k+1]=='\n'))
		if(session->protocol.pop3.pass!=NULL){
			free(session->protocol.pop3.pass);
			session->protocol.pop3.pass = NULL;
		}
		session->protocol.pop3.pass = (char *)getMemory(k+1, CHAR_TYPE);
		memset(session->protocol.pop3.pass, '\0', k+1);
		strncpy(session->protocol.pop3.pass, input,k);
	}
	else{
		addResponse(session->response, RESP_POP3_STATUS_KO);
	}
	return k;
}

int parseList(char *input, PTRSESSION session){
	int k = 0, start = 0;
	if(session->protocol.pop3.authState==AUTHORIZED){
		/*Controllo se ha il msgid come parametro*/
		if(session->protocol.pop3.msgID!=NULL){
			free(session->protocol.pop3.msgID);
			session->protocol.pop3.msgID = NULL;
		}
		while(isspace((unsigned int)input[k]))k++;
		start = k;
		while(!isspace((unsigned int)input[k]))k++;

		session->protocol.pop3.msgID = (char *)getMemory(k-start+1, CHAR_TYPE);
		memset(session->protocol.pop3.msgID, '\0', k-start+1);
		strncpy(session->protocol.pop3.msgID, input,k-start);
		if(strcmp("\r\n", session->protocol.pop3.msgID) == 0 || strcmp("", session->protocol.pop3.msgID) == 0){
			free(session->protocol.pop3.msgID);
			session->protocol.pop3.msgID = NULL;
		}

	}
	return k;
}

int parseRetr(char *input, PTRSESSION session){
	int k = 0;
	int start = 0;
	if(session->protocol.pop3.authState==AUTHORIZED){
		while(isspace(input[k]))k++;
		start = k;
		k++;
		while(!isspace(input[k]))k++;
		if(session->protocol.pop3.msgID!=NULL){
			free(session->protocol.pop3.msgID);
			session->protocol.pop3.msgID = NULL;
		}
		session->protocol.pop3.msgID = (char *)getMemory(k-start+1, CHAR_TYPE);
		memset(session->protocol.pop3.msgID, '\0', k-start+1);
		strncpy(session->protocol.pop3.msgID, &input[start],k-start);
	}
	else addResponse(session->response, RESP_POP3_STATUS_KO);

	return k;
}

int parseDele(char *input, PTRSESSION session){
	int k = 0;
	int start = 0;
	if(session->protocol.pop3.authState==AUTHORIZED){
		while(isspace(input[k]))k++;
		start = k;
		k++;
		while(!isspace(input[k])) k++; // && fromsocket[k+1]=='\n'))k++;
		if(session->protocol.pop3.msgID!=NULL){
			free(session->protocol.pop3.msgID);
			session->protocol.pop3.msgID = NULL;
		}
		session->protocol.pop3.msgID = (char *)getMemory(k-start+1, CHAR_TYPE);
		memset(session->protocol.pop3.msgID, '\0', k-start+1);
		strncpy(session->protocol.pop3.msgID, &input[start],k-start);
	}
	else addResponse(session->response, RESP_POP3_STATUS_KO);
	return k;
}


void executePass(PTRSESSION session, struct sockaddr_in * clientSockAddr, struct flock *fileLock, char * mboxPath){

	int size, k;
	int maildropSemId = -1;
	char *filename;

	if(isAuthorizedInSecretsFile(secretsFile, secretsFileSize, session->protocol.pop3.user, session->protocol.pop3.pass)==1){

		maildropSemId = getMBoxSem(session->protocol.pop3.user);
		binSemWait(maildropSemId);
		fileLock->l_type   = F_WRLCK;
		fileLock->l_whence = SEEK_SET;
		fileLock->l_start  = 0;
		fileLock->l_len    = 0;
		fileLock->l_pid    = getpid();
		size = strlen(session->protocol.pop3.user)+strlen(mboxPath)+5;//'.mbox'
		filename = (char*) getMemory(size+1,CHAR_TYPE);
		memset(filename,'\0',size+1);


		strcat(filename, mboxPath);
		strcat(filename, session->protocol.pop3.user);
		strcat(filename, ".mbox");
		session->protocol.pop3.mboxfd = openOrCreateFile(filename, WRITE ,&k);//k in questo caso non mi serve

		fcntl(*((int *)session->protocol.pop3.mboxfd), F_GETLK, fileLock);
		if(fileLock->l_type < 0){
			notifyError(ERR_FCNTL,0,0);
		}
		if(fileLock->l_type != F_UNLCK){
			session->protocol.pop3.authState = NO_STATE;
			addResponse(session->response, RESP_POP3_PASS_KO_LCK);
		}
		else {
			fileLock->l_type = F_WRLCK;
			fcntl(*((int *)session->protocol.pop3.mboxfd), F_SETLKW, fileLock);//Lock del file
			session->protocol.pop3.msgList = readMBox(session->protocol.pop3.mboxfd);//leggo la lista dei messaggi
			addResponse(session->response, RESP_POP3_PASS_OK);
			session->protocol.pop3.authState = AUTHORIZED;
		}

		free(filename);
	}
	else{
		addResponse(session->response, RESP_POP3_PASS_KO_WP);
	}
}

void executeList(PTRSESSION session){
	ARPAMSG arpamsg = NULL;
	int totalSize = 0;
	int msgNum = 0;
	char * msgNumStr = NULL;
	char * totalSizeStr = NULL;
	char * tmp = NULL;

	if(session->protocol.pop3.authState == AUTHORIZED){
		arpamsg = (session->protocol.pop3.msgID!=NULL)? getMsg(session->protocol.pop3.msgList, session->protocol.pop3.msgID) : NULL;
		if(arpamsg == NULL && session->protocol.pop3.msgID!=NULL){
			addResponse(session->response, RESP_POP3_LIST_NO_ID);
		}
		if(arpamsg != NULL){
			tmp = (char *)getMemory(1024,CHAR_TYPE);
			memset(tmp, '\0',1024);
			sprintf(tmp,"%s %d", arpamsg->msg_id, arpamsg->octets);
			addRspParam(session->rspParams, tmp);
			free(tmp);
			tmp = NULL;
			addResponse(session->response, RESP_POP3_LIST_ID_OK);
		}
		else{
			tmp = getMsgListChar(session->protocol.pop3.msgList);

			msgNum = countMsg(session->protocol.pop3.msgList);
			msgNumStr = (char *)getMemory(20, CHAR_TYPE);
			memset(msgNumStr, '\0', 20);
			sprintf(msgNumStr, "%d", msgNum);

			totalSize = getMailDropSize(session->protocol.pop3.msgList);
			totalSizeStr = (char *)getMemory(20, CHAR_TYPE);
			memset(totalSizeStr, '\0', 20);
			sprintf(totalSizeStr, "%d", totalSize);

			addRspParam(session->rspParams, msgNumStr);
			addRspParam(session->rspParams, totalSizeStr);
			addRspParam(session->rspParams, tmp);
			free(msgNumStr);
			free(totalSizeStr);
			free(tmp);
			tmp = NULL;
			addResponse(session->response, RESP_POP3_LIST_OK);
		}

	}
	else addResponse(session->response, RESP_POP3_STATUS_KO);
}

void executeRetr(PTRSESSION session){
	ARPAMSG arpamsg = NULL;
	int size;
	char *tmp = NULL;

	if(session->protocol.pop3.authState == AUTHORIZED){
		arpamsg = getMsg(session->protocol.pop3.msgList, session->protocol.pop3.msgID);
		if(arpamsg != NULL){
			size = 	strlen(FROM)+2 + strlen(arpamsg->from)+ 2 +
					strlen(DATE)+2 + strlen(arpamsg->date)+ 2 +
					strlen(TO)+2 + strlen(arpamsg->to)+ 2 +
					strlen(MSG_ID)+2+strlen(arpamsg->msg_id)+ 4 +
					strlen(arpamsg->body)+3;

			tmp = (char *)getMemory(size,CHAR_TYPE);
			memset(tmp, '\0', size);
			strcat(tmp,FROM);
			strcat(tmp,": ");
			strcat(tmp,arpamsg->from);
			strcat(tmp,"\r\n");
			strcat(tmp,DATE);
			strcat(tmp,": ");
			strcat(tmp,arpamsg->date);
			strcat(tmp,"\r\n");
			strcat(tmp,TO);
			strcat(tmp,": ");
			strcat(tmp,arpamsg->to);
			strcat(tmp,"\r\n");
			strcat(tmp,MSG_ID);
			strcat(tmp,": ");
			strcat(tmp,arpamsg->msg_id);
			strcat(tmp,"\r\n\r\n");
			strcat(tmp,arpamsg->body);
			strcat(tmp,"\r\n\r\n");
			addRspParam(session->rspParams, tmp);
			free(tmp);
			tmp = NULL;
			addResponse(session->response, RESP_POP3_RTR_OK);
		}
		else addResponse(session->response, RESP_POP3_RTR_KO);
	}
	else addResponse(session->response, RESP_POP3_STATUS_KO);
}

void executeDele(PTRSESSION session){
	ARPAMSG arpamsg = NULL;
	if(session->protocol.pop3.authState == AUTHORIZED){
		arpamsg = deleteMsg(session->protocol.pop3.msgList, session->protocol.pop3.msgID);
		if(arpamsg!= NULL){
			session->protocol.pop3.msgList = arpamsg;
			addResponse(session->response, RESP_POP3_DELE_OK);
		}
		else addResponse(session->response, RESP_POP3_DELE_KO);
	}
	else addResponse(session->response, RESP_POP3_STATUS_KO);
}

void executeQuit(PTRSESSION session, struct flock * fileLock){
	int maildropSemId = -1;
	if(session->protocol.pop3.mboxfd != NULL){
		session->protocol.pop3.msgList = removeDeletedMsg(session->protocol.pop3.msgList);
		lseek(*((int *)session->protocol.pop3.mboxfd), 0, SEEK_SET);
		if(ftruncate(*((int *)session->protocol.pop3.mboxfd), 0) < 0){
				notifyError(ERR_FILE_TRUNC,1,0);
		}
		writeMBox(session->protocol.pop3.mboxfd, session->protocol.pop3.msgList, 0);
		fileLock->l_type   = F_UNLCK;
		fcntl(*((int *)session->protocol.pop3.mboxfd), F_SETLK, &fileLock);
		closeFile(session->protocol.pop3.mboxfd);
		resetMsgList(session->protocol.pop3.msgList);
		maildropSemId = getMBoxSem(session->protocol.pop3.user);
		binSemPost(maildropSemId);
	}
	addResponse(session->response, RESP_POP3_QUIT);
}

void executeRset(PTRSESSION session){
	if(session->protocol.pop3.authState == AUTHORIZED){
		session->protocol.pop3.msgList = undoDeleteMsg(session->protocol.pop3.msgList);
		addResponse(session->response, RESP_POP3_RSET);
	}
	else addResponse(session->response, RESP_POP3_STATUS_KO);
}

void executeHelo(PTRSESSION session){
	regex_t pattern_buffer;
	if(REG_NOMATCH!= match_regex(&pattern_buffer,session->protocol.smtp.clienthostname, validIpAddressRegex) ||
			REG_NOMATCH!= match_regex(&pattern_buffer,session->protocol.smtp.clienthostname, validHostnameRegex)){
		addResponse(session->response, RESP_250);
	}
	else{
		addResponse(session->response, RESP_221);
	}
}

void executeMail(PTRSESSION session, struct sockaddr_in * clientSockAddr){
	regex_t pattern_buffer;
	/*"" e' il caso in cui il mailer daemon invia una notifica l'indirizzo puo' essere <>*/
	if(session->protocol.smtp.mailobject->sender!=NULL && (strcasecmp(session->protocol.smtp.mailobject->sender,"") ||
			REG_NOMATCH!= match_regex(&pattern_buffer,session->protocol.smtp.mailobject->sender, validEmailAddress))){

		/*Cambio stato, impostazione response*/
		session->protocol.smtp.mailobject->state = MAIL_RCVD;
		addResponse(session->response, RESP_250);
	}
	else{
		/*Cambio stato, impostazione response
		 * lo stato e' reimpostato al precedente (nessuno)
		 * */

		session->protocol.smtp.mailobject->state = NO_SESSION;
		addResponse(session->response, RESP_501);
	}
}

void executeRcpt(PTRSESSION session){
	int k = 0;
	regex_t pattern_buffer;
	if(session->protocol.smtp.mailobject->state == MAIL_RCVD || session->protocol.smtp.mailobject->state == RCPT_RCVD){

		while(session->protocol.smtp.mailobject->receiversTo[k] != '\0'
				&& REG_NOMATCH != match_regex(&pattern_buffer, session->protocol.smtp.mailobject->receiversTo[k], validEmailAddress))k++;

		if(session->protocol.smtp.mailobject->receiversTo[k]=='\0'){
			session->protocol.smtp.mailobject->state = RCPT_RCVD;
			addResponse(session->response, RESP_250);
		}
		else{
			addResponse(session->response, RESP_501);
		}
	}
	else{
		//Errore, ricevo RCPT prima di un comando MAIL reimposto lo stato
		session->protocol.smtp.mailobject->state = MAIL_RCVD;
		addResponse(session->response, RESP_503);
	}
}

void executeData(PTRSESSION session, CNF_PTR configuration){
	int k, end, size;
	pid_t mailWriterPid;
	char *cursor, *usrTemp, *filename;
	if(session->protocol.smtp.mailobject->state == RCPT_RCVD){
		/*Impostazioni per l'elaborazione del messaggio*/
		if(session->protocol.smtp.mailobject->mailType == INCOMING){

			/*Tutti i riceventi sono utenti locali (controllo in RCPT, parseCmd)
			 * Estraggo gli username e creo un processo/thread per ogni scrittura*/
			k = 0;
			if(session->protocol.smtp.mailobject->receiversTo!=NULL){
				while(session->protocol.smtp.mailobject->receiversTo[k]!='\0'){
					cursor = session->protocol.smtp.mailobject->receiversTo[k];
					end = 0;
					while(cursor[end]!='@')end++;
					usrTemp = (char *)getMemory(end+1, CHAR_TYPE);
					memset(usrTemp, '\0', end+1);
					strncpy(usrTemp, cursor, end);

					if((mailWriterPid=fork())==0){

						size = strlen(configuration->mailboxPath)+strlen(usrTemp)+6;//'.mbox\0'
						filename = (char*)getMemory(size,CHAR_TYPE);
						memset(filename,'\0',size);
						strcat(filename,configuration->mailboxPath);
						strcat(filename,usrTemp);
						strcat(filename,".mbox");

						writeMailToBox(filename, session, usrTemp);

						free(filename);
						filename = NULL;
						exit(0);
					}
					if(mailWriterPid < 0){
						notifyError(ERR_PROC_CREATE,1,0);
					}
					cursor = NULL;
					k++;
				}
			}

			session->protocol.smtp.mailobject = initMailObject(session->protocol.smtp.mailobject);
			addResponse(session->response, RESP_250);
		}
		else{
			/*TODO: Response messaggio non inviato e funzione non consentita per l'utente locale*/
		}
	}
	else{
		//Errore, ricevo DATA prima di un comando RCPT
		addResponse(session->response, RESP_503);
	}
}
